﻿Imports System.Collections.Generic


Namespace DoFactory.GangOfFour.Interpreter.RealWorld


    ''' <summary>
    ''' MainApp startup class for Real-World
    ''' Interpreter Design Pattern.
    ''' </summary>
    Public Class MainApp

        ''' <summary>
        ''' Entry point into console application.
        ''' </summary>
        Public Shared Sub Main()

            Dim roman As String = "MCMXXVIII"

            Dim context As New Context(roman)

            ' Build the 'parse tree'

            Dim tree As New List(Of Expression)()

            tree.Add(New ThousandExpression())
            tree.Add(New HundredExpression())
            tree.Add(New TenExpression())
            tree.Add(New OneExpression())

            ' Interpret
            For Each exp As Expression In tree
                exp.Interpret(context)
            Next
            Console.WriteLine("{0} = {1}", roman, context.Output)

            ' Wait for user
            'Console.ReadKey()

        End Sub

    End Class

    ''' <summary>
    ''' The 'Context' class
    ''' </summary>
    Class Context

        Private _input As String

        Private _output As Integer

        ' Constructor
        Public Sub New(ByVal input As String)
            Me._input = input
        End Sub

        ' Gets or sets input
        Public Property Input() As String
            Get
                Return _input
            End Get
            Set(ByVal value As String)
                _input = value
            End Set
        End Property

        ' Gets or sets output
        Public Property Output() As Integer
            Get
                Return _output
            End Get
            Set(ByVal value As Integer)
                _output = value
            End Set
        End Property
    End Class

    ''' <summary>
    ''' The 'AbstractExpression' class
    ''' </summary>
    MustInherit Class Expression
        Public Sub Interpret(ByVal context As Context)
            If context.Input.Length = 0 Then
                Return
            End If

            If context.Input.StartsWith(Nine()) Then
                context.Output += (9 * Multiplier())
                context.Input = context.Input.Substring(2)
            ElseIf context.Input.StartsWith(Four()) Then
                context.Output += (4 * Multiplier())
                context.Input = context.Input.Substring(2)
            ElseIf context.Input.StartsWith(Five()) Then
                context.Output += (5 * Multiplier())
                context.Input = context.Input.Substring(1)
            End If

            While context.Input.StartsWith(One())
                context.Output += (1 * Multiplier())
                context.Input = context.Input.Substring(1)
            End While

        End Sub

        Public MustOverride Function One() As String

        Public MustOverride Function Four() As String

        Public MustOverride Function Five() As String

        Public MustOverride Function Nine() As String

        Public MustOverride Function Multiplier() As Integer

    End Class

    ''' <summary>
    ''' A 'TerminalExpression' class
    ''' <remarks>
    ''' Thousand checks for the Roman Numeral M
    ''' </remarks>
    ''' </summary>
    Class ThousandExpression
        Inherits Expression

        Public Overrides Function One() As String
            Return "M"
        End Function

        Public Overrides Function Four() As String
            Return " "
        End Function

        Public Overrides Function Five() As String
            Return " "
        End Function

        Public Overrides Function Nine() As String
            Return " "
        End Function

        Public Overrides Function Multiplier() As Integer
            Return 1000
        End Function

    End Class

    ''' <summary>
    ''' A 'TerminalExpression' class
    ''' <remarks>
    ''' Hundred checks C, CD, D or CM
    ''' </remarks>
    ''' </summary>
    Class HundredExpression
        Inherits Expression

        Public Overrides Function One() As String
            Return "C"
        End Function

        Public Overrides Function Four() As String
            Return "CD"
        End Function

        Public Overrides Function Five() As String
            Return "D"
        End Function

        Public Overrides Function Nine() As String
            Return "CM"
        End Function

        Public Overrides Function Multiplier() As Integer
            Return 100
        End Function

    End Class

    ''' <summary>
    ''' A 'TerminalExpression' class
    ''' <remarks>
    ''' Ten checks for X, XL, L and XC
    ''' </remarks>
    ''' </summary>
    Class TenExpression
        Inherits Expression

        Public Overrides Function One() As String
            Return "X"
        End Function

        Public Overrides Function Four() As String
            Return "XL"
        End Function

        Public Overrides Function Five() As String
            Return "L"
        End Function

        Public Overrides Function Nine() As String
            Return "XC"
        End Function

        Public Overrides Function Multiplier() As Integer
            Return 10
        End Function

    End Class

    ''' <summary>
    ''' A 'TerminalExpression' class
    ''' <remarks>
    ''' One checks for I, II, III, IV, V, VI, VI, VII, VIII, IX
    ''' </remarks>
    ''' </summary>
    Class OneExpression
        Inherits Expression

        Public Overrides Function One() As String
            Return "I"
        End Function

        Public Overrides Function Four() As String
            Return "IV"
        End Function

        Public Overrides Function Five() As String
            Return "V"
        End Function

        Public Overrides Function Nine() As String
            Return "IX"
        End Function

        Public Overrides Function Multiplier() As Integer
            Return 1
        End Function

    End Class

End Namespace
